package pers.youqu.search.service.impl;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import pers.youqu.common.dto.PageDTO;
import pers.youqu.common.utils.EmptyUtil;
import pers.youqu.item.clients.ItemClient;
import pers.youqu.item.dto.SkuDTO;
import pers.youqu.item.dto.SpecParamDTO;
import pers.youqu.item.dto.SpuDTO;
import pers.youqu.search.entity.Goods;
import pers.youqu.search.repository.GoodsRepository;
import pers.youqu.search.service.IndexesService;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author Jason
 * @version 1.0.0
 * @date 2020/12/12 19:07
 * @Description TODO
 */
@Service
public class IndexesServiceImpl implements IndexesService {

    @Autowired
    private GoodsRepository goodsRepository;

    @Autowired
    private ItemClient itemClient;


    @Override
    public void deleteIndexes() {
        // 避免索引库冲突，添加前先删除
        try {
            goodsRepository.deleteIndex();
            System.out.println("删除索引库成功！");
        } catch (Exception e) {
            System.out.println("删除失败，要创建的索引库不存在");
        }
    }

    @Override
    public void createdNewIndexes() {
        System.out.println("===========开始新建索引库============");
        goodsRepository.createIndex("{\n" +
                "  \"settings\": {\n" +
                "    \"analysis\": {\n" +
                "      \"analyzer\": {\n" +
                "        \"my_pinyin\": {\n" +
                "          \"tokenizer\": \"ik_smart\",\n" +
                "          \"filter\": [\n" +
                "            \"py\"\n" +
                "          ]\n" +
                "        }\n" +
                "      },\n" +
                "      \"filter\": {\n" +
                "        \"py\": {\n" +
                "\t\t  \"type\": \"pinyin\",\n" +
                "          \"keep_full_pinyin\": true,\n" +
                "          \"keep_joined_full_pinyin\": true,\n" +
                "          \"keep_original\": true,\n" +
                "          \"limit_first_letter_length\": 16,\n" +
                "          \"remove_duplicated_term\": true\n" +
                "        }\n" +
                "      }\n" +
                "    }\n" +
                "  },\n" +
                "  \"mappings\": {\n" +
                "    \"properties\": {\n" +
                "      \"id\": {\n" +
                "        \"type\": \"keyword\"\n" +
                "      },\n" +
                "      \"suggestion\": {\n" +
                "        \"type\": \"completion\",\n" +
                "        \"analyzer\": \"my_pinyin\",\n" +
                "        \"search_analyzer\": \"ik_smart\"\n" +
                "      },\n" +
                "      \"title\":{\n" +
                "        \"type\": \"text\",\n" +
                "        \"analyzer\": \"my_pinyin\",\n" +
                "        \"search_analyzer\": \"ik_smart\"\n" +
                "      },\n" +
                "      \"image\":{\n" +
                "        \"type\": \"keyword\",\n" +
                "        \"index\": false\n" +
                "      },\n" +
                "      \"updateTime\":{\n" +
                "        \"type\": \"date\"\n" +
                "      },\n" +
                "      \"specs\":{\n" +
                "        \"type\": \"nested\",\n" +
                "        \"properties\": {\n" +
                "          \"name\":{\"type\": \"keyword\" },\n" +
                "          \"value\":{\"type\": \"keyword\" }\n" +
                "        }\n" +
                "      }\n" +
                "    }\n" +
                "  }\n" +
                "}");
    }

    @Override
    public void bulkInsertData() {

        Integer page = 1;
        Integer rows = 50;

        Long totals;

        do {
            PageDTO<SpuDTO> spuByPage = itemClient.findSpuByPage(null, null, null, page++, rows, true);
            totals = spuByPage.getTotal();

            List<Goods> goodsList = spuByPage.getItems().stream().map(this::buildGoods).collect(Collectors.toList());

            System.out.println("================= goodsList ============= \n" + goodsList);

            goodsRepository.saveAll(goodsList);

        } while ((page - 1) * rows < totals);


    }

    @Override
    public void saveGoodsById(Long spuId) {
        PageDTO<SpuDTO> spuByPage = itemClient.findSpuByPage(null, null, spuId, 1, 1, true);
        if (spuByPage.getTotal() == 1) {
            goodsRepository.save(buildGoods(spuByPage.getItems().get(0)));
        }

    }

    @Override
    public void deleteGoodsById(Long spuId) {
        goodsRepository.deleteById(spuId);
    }


    private Goods buildGoods(SpuDTO spuDTO) {
        Goods goods = new Goods();
        BeanUtils.copyProperties(spuDTO, goods);

        // ============分类id=============
        goods.setCategoryId(spuDTO.getCid3());

        // ============更新时间=============
        goods.setUpdateTime(new Date());

        //==============侯选值【搜索框补全使用】，满足搜索提示：商品名，品牌 + 商品名，分类 + 品牌，品牌 + 分类=============
        List<String> suggestList = new ArrayList<>();

        String goodsName = spuDTO.getName();
        String categoryName = spuDTO.getCategoryName().split("/")[2];
        String brandName = StringUtils.substringBefore(spuDTO.getBrandName(), "（");

        // 商品名称
        suggestList.add(goodsName);
        // 品牌 + 商品名称
        suggestList.add(goodsName.contains(brandName) ? brandName : brandName + goodsName);
        // 分类 + 品牌
        suggestList.add(categoryName + brandName);
        // 品牌 + 分类
        suggestList.add(brandName + categoryName);

        goods.setSuggestion(suggestList);

        // ==================商品标题====================
        String title = goodsName + " " + brandName + " " + categoryName;
        goods.setTitle(title);

        // 查询SKU填充goods信息
        List<SkuDTO> skuDTOS = itemClient.findSkuBySpuId(spuDTO.getId());

        // =========存储价格：set去重==========
        Set<Long> prices = new HashSet<>();
        // ==========计算spu中所有sku的销量=========
        Long sold = 0L;

        for (SkuDTO skuDTO : skuDTOS) {
            prices.add(skuDTO.getPrice());
            sold += skuDTO.getSold();
        }

        // ==============价格展示================
        goods.setPrices(prices);
        // ==================销量============
        goods.setSold(sold);


        // ==============spu图片====================
        goods.setImage(StringUtils.substringBefore(skuDTOS.get(0).getImages(), ","));


        // =========specs：可以搜索的规格参数和值========
        List<Map<String, Object>> specs = itemClient.findSpuAllParamBySpuId(spuDTO.getId(), true)
                .stream()
                .map(specParamDTO -> {
                    Map<String, Object> resultMap = new HashMap<>();
                    resultMap.put("name", specParamDTO.getName());

                    // value如果是数值的，有区间，选择区间
                    resultMap.put("value", chooseSegment(specParamDTO));
                    return resultMap;
                }).collect(Collectors.toList());


        goods.setSpecs(specs);

        return goods;
    }

    private Object chooseSegment(SpecParamDTO specParamDTO) {
        // 获取参数值
        Object value = specParamDTO.getValue();


        // value没值
        if (EmptyUtil.isNullOrEmpty(value)) {
            return "其它";
        }
        // 不是数值，没有区间，是集合直接返回值【排除区间】
        if (!specParamDTO.getNumeric() || StringUtils.isBlank(specParamDTO.getSegments()) || value instanceof Collection) {
            return value;
        }

        // ========= 是数值，有区间的情况 ===========
        double val = parseDouble(value.toString());
        String result = "其他";

        // 获取数值段
        for (String segments : specParamDTO.getSegments().split(",")) {
            String[] minToMaxArray = segments.split("-");

            // 获取最小值
            double min = parseDouble(minToMaxArray[0]);
            // 没有最大范围就取最大Double最大值
            double max = Double.MAX_VALUE;

            // 获取最大值
            if (minToMaxArray.length == 2) {
                max = parseDouble(minToMaxArray[1]);
            }

            // 判断属于哪个区间
            if (val >= min && val < max) {
                if (minToMaxArray.length == 1) {
                    // 拼接区间字符串
                    result = minToMaxArray[0] + specParamDTO.getUnit() + "以上";
                } else if (min == 0) {
                    result = minToMaxArray[1] + specParamDTO.getUnit() + "以下";
                } else {
                    result = segments + specParamDTO.getUnit();
                }
                break;
            }

        }
        return result;
    }

    /**
     * 将字符串转换成Double类型数值
     *
     * @param str 字符串
     * @return 解析错误返回 null
     */
    private double parseDouble(String str) {
        try {
            return Double.parseDouble(str);
        } catch (Exception e) {
            return 0;
        }
    }


}
